home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Carousel
/
CAROUSEL.cdr
/
mactosh
/
utilprn
/
hpdeskje.sit
/
HPDJet ƒ
/
PDEF0.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-04-02
|
14KB
|
467 lines
/* 02.04.1989 amn (latest edit) */
/* PDEF0.c - printer driver for Macintosh and HP DeskJet, draft printing. */
/* Compiles into 'PDEF' resource, id 0, name ''. */
/* We cannot use any global variables in this code. However, the globals of the */
/* low-level driver (XPrint) are available thru the handle 'dCtlStorage' in the */
/* driver's device control entry. */
/* This resource is placed into the printer resource file */
/* 'HP DeskJet', type 'PRER', creator 's89^' as */
/* 'PDEF' 0 '' by 'PRER_Builder' utility program. This utility adds a small jump */
/* table in front of the code produced by LightspeedC. */
/* These procedures handle draft printing, ie. direct commands to printer. */
/* HP DeskJet is quite capable of accepting direct print head positioning: */
/* it tries to accumulate print data in its 16 kB buffer and sort it out */
/* to print it in optimal order. Thus we don't try to avoid reverse line feeds. */
/* Authors: Ari Mujunen (amn@hutcs.hut.fi) and Olli Arnberg (oar@hutcs.hut.fi). */
/* Copyright Ari Mujunen, Olli Arnberg 1989. */
/* You may redistribute the driver (=printer resource file, source files, */
/* documentation file(s), and the file 'Copyright and Source Offer') */
/* only _non-commercially_ and _in its entirety_. */
/* See the file 'Copyright and Source Offer' and/or documentation for details. */
/* Acknowledgements: Special thanks to Mr. Earle R. Horton for his 'Daisy' */
/* daisywheel printer driver and its source code published in 'MacTutor', Nov-Dec 1987. */
/* This driver served as a basis and inspiration for our work. It also */
/* proofed that a Macintosh printer driver can be done despite the lack of */
/* documentation from Apple. */
/* Change history: */
/* Version When Who Why */
/* 2.0 21.11.1988 amn Original rewrite. */
/* 23.11.1988 amn Simplistic draft (direct positioning commands to printer). */
/* 24.11.1988 amn Read printed listing... */
/* 25.11.1988 amn Implementing justified text, ie. SpaceExtra. */
/* 27.11.1988 amn Implementing justified text, ie. SpaceExtra. */
/* 09.12.1988 amn User-specifiable setting 'movePrintPositionBeforeEachWord'. */
/* 12.12.1988 amn HP DeskJet physical margins taken into account. */
/* 07.03.1989 amn Character conversion table from Mac to HP Roman8. */
/* 10.03.1989 amn Call stdText with Ptr, not QDPtr to text buffer. */
/* 25.03.1989 amn,oar The global file refNums are not used any longer because of MF. */
/* 28.03.1989 amn Settable printer origin. */
/* 2.1 02.04.1989 amn,oar Released version. */
#include "common_mac_includes.h"
/* Mac OS includes specific to this module: */
#include <pascal.h>
#include "prglobals.h"
#include "procedures_for_PDEF1.c"
#include "procedures_for_PDEF5.c"
/* Function prototypes. */
/* Procedure dispatcher. */
void main(int);
/* Initializes a specialized grafPort for printing. */
pascal TPPrPort myPrOpenDoc(THPrint, TPPrPort, Ptr);
/* Disposes the printing grafPort. */
pascal void myPrCloseDoc(TPPrPort);
/* Reinitializes the printing grafPort. */
pascal void myPrOpenPage(TPPrPort, TPRect);
/* Feeds next sheet. :-) */
pascal void myPrClosePage(TPPrPort);
/* Replaces the standard QuickDraw low-level procedure for drawing text. */
pascal void myStdText(int, Ptr, Point, Point);
void printOneWord(int, Ptr, Point, Point);
/* Used to call standard QD text-drawing procedure. We use prototypes... */
pascal void CallPascal(int, Ptr, Point, Point, Ptr);
/* Function definitions. */
void
main(routineSelector)
int routineSelector;
{
/* The jump table code inserted before our code resource by 'PRER_Builder' */
/* utility program pushes a word onto stack indicating which routine is called. */
/* We pop it off the stack and select an appropriate routine. */
switch(routineSelector) {
case 0:
asm {
unlk a6 ;; LSC generates an 'link' instruction to access parameters
move.l (a7)+, d0 ;; pop return address to our jump table code (discarded)
move.w (a7)+, d0 ;; pop argument 'routineSelector'
jmp myPrOpenDoc
}
case 1:
asm {
unlk a6
move.l (a7)+, d0
move.w (a7)+, d0
jmp myPrCloseDoc
}
case 2:
asm {
unlk a6
move.l (a7)+, d0
move.w (a7)+, d0
jmp myPrOpenPage
}
case 3:
asm {
unlk a6
move.l (a7)+, d0
move.w (a7)+, d0
jmp myPrClosePage
}
} /* switch */
/* We should not arrive here; Printing Manager has called a non-existent routine. */
SysError(5); /* check bounds trap ??? */
} /* main */
/*
This function is supposed to return a pointer to a specialized GrafPort (a TPrPort) customized
for printing. Due to the paucity of documentation on how to go about this, I do not know whether
I am going about this in exactly the right way, but I sure hope so. I set portBits.bounds for
the port to the empty Rect (0,0,0,0) and then install the standard QuickDraw routines as
GrafProcs. In place of StdText, I put my own StdText routine. Hopefully, QuickDraw will keep
track of the correct pen location for me, and call my routine whenever it is necessary to draw
text.
Other tasks: save a copy of the user print record in the printer resource file
to remember user's last choices in job dialog (resolution etc.).
*/
#define DEBUG_OPEN_PRINT_RECORD
pascal TPPrPort
myPrOpenDoc(hPrint, pPrPort, pIOBuf)
THPrint hPrint;
TPPrPort pPrPort;
Ptr pIOBuf;
{
TPPrPort thisPort;
ptXprintGlobals xPrintGlobals;
ptPrParam pXPrintParameterBlock;
OSErr retCode;
{ /* Lock this code resource in memory (Printing Manager should do this, but...). */
Handle us;
us = (Handle)GetResource('PDEF', 0);
if (us == nil) {
PrintErr = ResError();
return(nil);
}
HLock(us);
}
if (pPrPort == nil) { /* printing GrafPort NOT preallocated */
if ((thisPort = (TPPrPort)NewPtr((long)sizeof(TPrPort))) == nil) {
PrintErr = iMemFullErr;
return(nil);
}
thisPort->fOurPtr = TRUE;
}
else { /* printing GrafPort already preallocated */
thisPort = pPrPort;
thisPort->fOurPtr = FALSE;
}
xPrintGlobals = GET_XPRINT_GLOBALS;
pXPrintParameterBlock = &xPrintGlobals->xPrintParameterBlock;
/* Initialize GrafPort */
OpenPort(&thisPort->gPort);
setRectsAndRgns(thisPort, hPrint);
/* Fill out QuickDraw low-level drawing procedures (gProcs) for this port. */
SetStdProcs(&thisPort->gProcs);
thisPort->gProcs.textProc = (QDPtr)myStdText;
thisPort->gPort.grafProcs = &thisPort->gProcs;
/* Initialize the printer using standard printer control call. */
pXPrintParameterBlock->csCode = iPrDevCtl;
pXPrintParameterBlock->lParam1 = lPrReset;
if ((retCode = PBControl(pXPrintParameterBlock, FALSE)) != noErr)
goto cleanUp;
#define NUMBER_OF_THIS_PDEF 0
#include "save_last_used.c"
/* Page range etc. are available in global print record. */
xPrintGlobals->printRecord = **hPrint;
/* If application has not requested an own idle procedure, we set our default one. */
if (xPrintGlobals->printRecord.prJob.pIdleProc == nil)
xPrintGlobals->printRecord.prJob.pIdleProc = (ProcPtr)checkForCommandPeriod;
/* High-level printing code always counts pages from 1 (IM II-156). */
xPrintGlobals->pageCounter = 1;
retCode = noErr;
cleanUp:
PrintErr = retCode;
if (retCode == noErr)
return(thisPort);
else {
if (thisPort->fOurPtr)
DisposPtr(thisPort);
return(nil);
}
} /* myOpenDoc */
pascal void
myPrCloseDoc(pPrPort)
TPPrPort pPrPort;
{
if (pPrPort == nil)
return;
ClosePort(pPrPort);
if (pPrPort->fOurPtr)
DisposPtr(pPrPort);
} /* myPrCloseDoc */
pascal void
myPrOpenPage(pPrPort, pPageFrame)
TPPrPort pPrPort;
TPRect pPageFrame;
{
ptXprintGlobals xPrintGlobals;
TPPrint pPrint;
if (pPrPort == nil)
return;
/* Don't touch 'pPageFrame' in draft mode (IM II-159). */
xPrintGlobals = GET_XPRINT_GLOBALS;
/* Port should be returned to initial state (as initialized in OpenDoc). ??? */
InitPort(pPrPort);
pPrint = &xPrintGlobals->printRecord;
setRectsAndRgns(pPrPort, &pPrint);
/* Fill out QuickDraw low-level drawing procedures (gProcs) for this port. */
SetStdProcs(&pPrPort->gProcs);
pPrPort->gProcs.textProc = (QDPtr)myStdText;
pPrPort->gPort.grafProcs = &pPrPort->gProcs;
/* if (PrintErr != noErr) then some kind of error has occurred during previous page. */
/* Applications shouldn't call us then, but... */
if ((xPrintGlobals->pageCounter >= xPrintGlobals->printRecord.prJob.iFstPage)
&& (xPrintGlobals->pageCounter <= xPrintGlobals->printRecord.prJob.iLstPage)
&& (PrintErr == noErr)
&& (xPrintGlobals->printRecord.prStl.feed == feedCut))
if (waitNextPage() == FALSE) /* Dialog 'Insert next sheet...' */
PrintErr = iPrAbort;
} /* myPrOpenPage */
pascal void
myPrClosePage(pPrPort)
TPPrPort pPrPort;
{
ptXprintGlobals xPrintGlobals;
ptPrParam pXPrintParameterBlock;
OSErr retCode;
if (pPrPort == nil)
return;
/* if (PrintErr != noErr) then some kind of error has occurred during page. */
/* Applications will call us nevertheless. */
xPrintGlobals = GET_XPRINT_GLOBALS;
pXPrintParameterBlock = &xPrintGlobals->xPrintParameterBlock;
if ((xPrintGlobals->pageCounter >= xPrintGlobals->printRecord.prJob.iFstPage)
&& (xPrintGlobals->pageCounter <= xPrintGlobals->printRecord.prJob.iLstPage)) {
/* Form feed using standard printer control call. */
pXPrintParameterBlock->csCode = iPrDevCtl;
pXPrintParameterBlock->lParam1 = lPrPageEnd;
if ((retCode = PBControl(pXPrintParameterBlock, FALSE)) != noErr)
PrintErr = retCode;
}
xPrintGlobals->pageCounter++;
} /* myClosePage */
/*** #define DEBUG_TEXT_DRAWING ***/
pascal void
myStdText(byteCount, textBuffer, numer, denom)
int byteCount;
Ptr textBuffer;
Point numer, denom;
{
ptXprintGlobals xPrintGlobals;
GrafPtr savePort;
xPrintGlobals = GET_XPRINT_GLOBALS;
GetPort(&savePort);
(*(xPrintGlobals->printRecord.prJob.pIdleProc))();
SetPort(savePort);
if ((xPrintGlobals->pageCounter >= xPrintGlobals->printRecord.prJob.iFstPage)
&& (xPrintGlobals->pageCounter <= xPrintGlobals->printRecord.prJob.iLstPage)
&& (PrintErr == noErr))
{
int i, startOfWord;
GrafPtr gp;
#define CHARACTERS 0
#define BLANKS 1
startOfWord = 0;
GetPort(&gp);
if ((!(xPrintGlobals->currentSettings.movePrintPositionBeforeEachWord))
&& (gp->spExtra == 0L))
/* we assume that accurate positioning of word beginnings is not required */
i = byteCount + 1;
else {
int state;
i = 0;
state = CHARACTERS;
while(i<=byteCount) {
switch(state) {
case CHARACTERS:
if (textBuffer[i] == ' ')
state = BLANKS;
else
i++;
break;
case BLANKS:
if (textBuffer[i] == ' ')
i++;
else {
printOneWord(i-startOfWord, &textBuffer[startOfWord], numer, denom);
startOfWord = i;
state = CHARACTERS;
}
break;
} /* switch */
} /* while */
}
/* Last (or only) word of this string. */
printOneWord(i-startOfWord-1, &textBuffer[startOfWord], numer, denom);
} /* if printing allowed */
} /* myStdText */
void
printOneWord(byteCount, textBuffer, numer, denom)
int byteCount;
Ptr textBuffer;
Point numer, denom;
{
ptXprintGlobals xPrintGlobals;
ptPrParam pXPrintParameterBlock;
Point thePoint;
long theLong;
Str255 theNumAsString;
QDProcs stdProcs;
StringHandle ct; /* character conversion table */
int i;
Str255 convertedDeskJetWord;
xPrintGlobals = GET_XPRINT_GLOBALS;
pXPrintParameterBlock = &xPrintGlobals->xPrintParameterBlock;
GetPen(&thePoint);
LocalToGlobal(&thePoint); /* Someone may have adjusted the origin. */
#ifdef DEBUG_TEXT_DRAWING
printString((StringPtr)"\pAt (");
NumToString((long)thePoint.v, theNumAsString);
printString(theNumAsString);
printString((StringPtr)"\p,");
NumToString((long)thePoint.h, theNumAsString);
printString(theNumAsString);
printString((StringPtr)"\p) scaled ((");
NumToString((long)numer.v, theNumAsString);
printString(theNumAsString);
printString((StringPtr)"\p/");
NumToString((long)denom.v, theNumAsString);
printString(theNumAsString);
printString((StringPtr)"\p),(");
NumToString((long)numer.h, theNumAsString);
printString(theNumAsString);
printString((StringPtr)"\p/");
NumToString((long)denom.h, theNumAsString);
printString(theNumAsString);
printString((StringPtr)"\p)) ");
NumToString((long)byteCount, theNumAsString);
printString(theNumAsString);
printString((StringPtr)"\p characters:\r\n->");
#else
/* Position print head.*/
printString((StringPtr)"\p\033&a");
theLong = (long)thePoint.v * 720L / (long)xPrintGlobals->printRecord.prInfo.iVRes;
NumToString(theLong, theNumAsString);
printString(theNumAsString);
printString((StringPtr)"\pV");
printString((StringPtr)"\p\033&a");
theLong = (long)thePoint.h * 720L / (long)xPrintGlobals->printRecord.prInfo.iHRes;
NumToString(theLong, theNumAsString);
printString(theNumAsString);
printString((StringPtr)"\pH");
#endif DEBUG_TEXT_DRAWING
/* Convert characters from Mac code set to HP Roman8 using C89T-resource. */
if ((ct = (StringHandle)GetResource('C89T', 0)) != nil) {
LoadResource(ct);
for(
i=0;
i < ((byteCount>sizeof(convertedDeskJetWord))
?(sizeof(convertedDeskJetWord))
:byteCount);
i++
)
convertedDeskJetWord[i] = (*ct)[((unsigned char *)textBuffer)[i]];
pXPrintParameterBlock->lParam1 = (long)(&convertedDeskJetWord);
pXPrintParameterBlock->lParam2 = (long)(i);
}
else {
pXPrintParameterBlock->lParam1 = (long)textBuffer;
pXPrintParameterBlock->lParam2 = (long)byteCount;
}
/* Send actual text. */
pXPrintParameterBlock->csCode = iPrIOCtl;
/* retCode = */ PBControl(pXPrintParameterBlock, FALSE);
/* This must remain synchronous I/O, otherwise the local buffer may disappear. */
#ifdef DEBUG_TEXT_DRAWING
printString((StringPtr)"\p<-\r\n");
#endif DEBUG_TEXT_DRAWING
/* Move pen. */
SetStdProcs(&stdProcs);
CallPascal(byteCount, textBuffer, numer, denom, stdProcs.textProc);
} /* printOneWord */